﻿using System;
using System.ComponentModel;

namespace Deepforest.WPF.Controls.Data
{
    public class Property : Item, IDisposable
    {
        #region Fields

        private object _instance;
        private PropertyDescriptor _property;

        #endregion

        #region Initialization

        public Property(object instance, PropertyDescriptor property)
        {
            this._instance = instance;
            this._property = property;

            this._property.AddValueChanged(_instance, instance_PropertyChanged);
        }

        #endregion

        #region Properties

        /// <value>
        /// Initializes the reflected instance property
        /// </value>
        /// <exception cref="NotSupportedException">
        /// The conversion cannot be performed
        /// </exception>
        public object Value
        {
            get { return _property.GetValue(_instance); }
            set
            {
                object currentValue = _property.GetValue(_instance);
                if (value != null && value.Equals(currentValue))
                {
                    return;
                }
                Type propertyType = _property.PropertyType;
                if (propertyType == typeof(object) ||
                    value == null && propertyType.IsClass ||
                    value != null && propertyType.IsAssignableFrom(value.GetType()))
                {
                    _property.SetValue(_instance, value);
                }
                else
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(_property.PropertyType);
                    object convertedValue = converter.ConvertFrom(value);
                    _property.SetValue(_instance, convertedValue);
                }
            }
        }

        public string Name
        {
            get { return _property.Name; }
        }

        public bool IsWriteable
        {
            get { return !IsReadOnly; }
        }

        public bool IsReadOnly
        {
            get { return _property.IsReadOnly; }
        }

        public Type PropertyType
        {
            get { return _property.PropertyType; }
        }

        public string Category
        {
            get { return _property.Category; }
        }

        #endregion

        #region Event Handlers

        void instance_PropertyChanged(object sender, EventArgs e)
        {
            NotifyPropertyChanged("Value");
        }

        #endregion

        #region IDisposable Members

        protected override void Dispose(bool disposing)
        {
            if (Disposed)
            {
                return;
            }
            if (disposing)
            {
                _property.RemoveValueChanged(_instance, instance_PropertyChanged);
            }
            base.Dispose(disposing);
        }

        #endregion
    }
}
